package com.github.jokar.customizeview.widget

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.graphics.Paint.ANTI_ALIAS_FLAG
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import com.github.jokar.customizeview.R

/**
 * Created by JokAr on 2017/10/24.
 */
class RulerView @JvmOverloads constructor(context: Context,
                                          attrs: AttributeSet?,
                                          defStyleAttr: Int)
    : View(context, attrs, defStyleAttr) {
    constructor(context: Context, attrs: AttributeSet? = null) : this(context, attrs, 0)
    constructor(context: Context) : this(context, null)

    /**
     * 尺子高度
     */
    var rulerHeight = 50f
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 尺子距离顶部位置
     */
    var rulerToResultSpacing = rulerHeight / 4
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 刻度平分多少份
     */
    var scaleCount = 10
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 刻度间距
     */
    var scaleSpacing = 20f
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 最小刻度
     */
    var minScale = 0
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 最大刻度
     */
    var maxScale = 50
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 第一次显示的刻度
     */
    var firstScale: Float = minScale.toFloat()
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 背景画笔
     */
    private var bgPaint = Paint(ANTI_ALIAS_FLAG)
    /**
     * 小刻度画笔
     */
    private var smallScalePaint = Paint(ANTI_ALIAS_FLAG)
    /**
     * 中刻度画笔
     */
    private var middleScalePaint = Paint(ANTI_ALIAS_FLAG)
    /**
     * 大刻度画笔
     */
    private var largeScalePaint = Paint(ANTI_ALIAS_FLAG)
    /**
     * 刻度值画笔
     */
    private var scaleNumPaint = Paint(ANTI_ALIAS_FLAG)

    private var scaleNumRect = Rect()
    /**
     * 背景颜色
     */
    private var bgColor = Color.RED
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 背景圆角大小
     */
    var bgRadius = 10f
        set(value) {
            field = value
            invalidate()
        }

    /**
     * 小刻度颜色
     */
    var smallScaleColor = Color.parseColor("#0FF999")
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 中刻度颜色
     */
    var middleScaleColor = Color.parseColor("#0FF666")
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 大刻度颜色
     */
    var largeScaleColor = Color.parseColor("#0FF50B")
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 刻度值颜色
     */
    var scaleNumColor = Color.parseColor("#0FF333")
        set(value) {
            field = value
            invalidate()
        }
    /**
     * view的宽高
     */
    var viewHeight = 0
    var viewWidth = 0
    /**
     * 小刻度高度
     */
    var smallScaleHeight = 0f
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 中刻度高度
     */
    var middleScaleHeight = 0f
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 大刻度高度
     */
    var largeScaleHeight = 0f
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 小刻度大小
     */
    var smallScaleStroke = 1
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 中刻度大小
     */
    var middleScaleStroke = 2
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 大刻度大小
     */
    var largeScaleStroke = 3
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 刻度字体大小
     */
    var scaleNumStroke = 16
        set(value) {
            field = value
            invalidate()
        }

    private var bgRect = RectF()
    /**
     * 记录当前移动的位置
     */
    private var moveX = 0f
    private var lastMoveX = 0f
    /**
     * 记录draw过程中canvas偏移的x位置
     */
    private var rulerRight = 0f
    /**
     * 跟踪触摸事件
     */
    private var velocityTracker = VelocityTracker.obtain()

    private var currentX = 0f
    private var downX = 0f

    private var endAnimator: ValueAnimator? = null
    private var isTouchUp = false

    private var leftScroll = 0
    private var rightScroll = 0

    init {
        setAttrs(attrs, defStyleAttr)

        //
        bgPaint.color = bgColor
        bgPaint.style = Paint.Style.FILL
        bgPaint.isAntiAlias = true
        //
        smallScalePaint.color = smallScaleColor
        smallScalePaint.strokeWidth = smallScaleStroke.toFloat()
        smallScalePaint.style = Paint.Style.FILL
        smallScalePaint.strokeCap = Paint.Cap.ROUND
        smallScalePaint.isAntiAlias = true
        //
        middleScalePaint.color = middleScaleColor
        middleScalePaint.style = Paint.Style.FILL
        middleScalePaint.strokeWidth = middleScaleStroke.toFloat()
        middleScalePaint.strokeCap = Paint.Cap.ROUND
        middleScalePaint.isAntiAlias = true
        //
        largeScalePaint.color = largeScaleColor
        largeScalePaint.style = Paint.Style.FILL
        largeScalePaint.strokeCap = Paint.Cap.ROUND
        largeScalePaint.strokeWidth = largeScaleStroke.toFloat()
        largeScalePaint.isAntiAlias = true
        //
        scaleNumPaint.color = scaleNumColor
        scaleNumPaint.textSize = scaleNumStroke.toFloat()
        scaleNumPaint.isAntiAlias = true

        //
        smallScaleHeight = rulerHeight / 4
        middleScaleHeight = rulerHeight / 2
        largeScaleHeight = rulerHeight / 2 + 10
    }

    private fun setAttrs(attrs: AttributeSet?, defStyleAttr: Int) {
        val typArray = context.obtainStyledAttributes(attrs, R.styleable.RulerView,
                defStyleAttr, 0)
        bgColor = typArray.getColor(R.styleable.RulerView_bgColor, bgColor)
        smallScaleColor = typArray.getColor(R.styleable.RulerView_smallScaleColor, smallScaleColor)
        middleScaleColor = typArray.getColor(R.styleable.RulerView_middleScaleColor, middleScaleColor)
        largeScaleColor = typArray.getColor(R.styleable.RulerView_largeScaleColor, largeScaleColor)
        scaleNumColor = typArray.getColor(R.styleable.RulerView_scaleNumColor, scaleNumColor)
        smallScaleStroke = typArray.getDimensionPixelSize(R.styleable.RulerView_smallScaleStroke,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, smallScaleStroke.toFloat(),
                        resources.displayMetrics).toInt())
        middleScaleStroke = typArray.getDimensionPixelSize(R.styleable.RulerView_middleScaleStroke,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, middleScaleStroke.toFloat(),
                        resources.displayMetrics).toInt())
        largeScaleStroke = typArray.getDimensionPixelSize(R.styleable.RulerView_largeScaleStroke,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, largeScaleStroke.toFloat(),
                        resources.displayMetrics).toInt())
        scaleNumStroke = typArray.getDimensionPixelSize(R.styleable.RulerView_scaleNumStroke,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scaleNumStroke.toFloat(),
                        resources.displayMetrics).toInt())
        bgRadius = typArray.getDimensionPixelSize(R.styleable.RulerView_bgRadius,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, bgRadius,
                        resources.displayMetrics).toInt()).toFloat()
        rulerHeight = typArray.getDimensionPixelSize(R.styleable.RulerView_rulerHeight,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rulerRight,
                        resources.displayMetrics).toInt()).toFloat()
        rulerToResultSpacing = typArray.getDimensionPixelSize(R.styleable.RulerView_rulerToResultSpacing,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rulerToResultSpacing,
                        resources.displayMetrics).toInt()).toFloat()
        scaleSpacing = typArray.getDimensionPixelSize(R.styleable.RulerView_scaleSpacing,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scaleSpacing,
                        resources.displayMetrics).toInt()).toFloat()
        firstScale = typArray.getFloat(R.styleable.RulerView_firstScale, firstScale)
        maxScale = typArray.getInt(R.styleable.RulerView_maxScale, maxScale)
        minScale = typArray.getInt(R.styleable.RulerView_minScale, minScale)
        typArray.recycle()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)

        viewWidth = widthSize + paddingLeft + paddingRight
        when (heightMode) {
            MeasureSpec.AT_MOST ->
                viewHeight = (rulerHeight + paddingTop + paddingBottom + rulerToResultSpacing * 2).toInt()
            MeasureSpec.EXACTLY,
            MeasureSpec.UNSPECIFIED ->
                viewHeight = heightSize + paddingBottom + paddingTop
        }

        setMeasuredDimension(viewWidth, viewHeight)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //画背景
        drawBG(canvas)
        //画尺子
        drawScale(canvas)
    }

    /**
     * 触摸事件
     */
    override fun onTouchEvent(event: MotionEvent): Boolean {
        isTouchUp = false
        currentX = event.x
        velocityTracker.computeCurrentVelocity(500)
        velocityTracker.addMovement(event)
        //
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downX = event.x
            }
            MotionEvent.ACTION_MOVE -> {
//                println("currentX: $currentX, downX: $downX, lastMoveX: $lastMoveX")
                //移动的位置 = 手指移动的位置 - 手指按下的位置 + 上次滑动后移动的位置
                moveX = currentX - downX + lastMoveX

                if (moveX >= viewWidth / 2) {  //判断是否到了最小刻度位置
                    moveX = (viewWidth / 2).toFloat()

                } else if (moveX <= getLargeScaleMoveX(maxScale.toFloat())) { //判断是否到了最大位置
                    moveX = getLargeScaleMoveX(maxScale.toFloat())

                }
            }
            MotionEvent.ACTION_UP -> {
                lastMoveX = moveX
                autoVelocityScroll(velocityTracker.xVelocity.toInt())
                velocityTracker.clear()
            }
        }

        invalidate()
        return true
    }

    private fun autoVelocityScroll(xVelocity: Int) {
        if (Math.abs(xVelocity) < 50) {
            isTouchUp = true
            return
        }

        if (endAnimator != null && endAnimator!!.isRunning) {
            return
        }
        //
        endAnimator = ValueAnimator.ofInt(0, xVelocity / 20)
        endAnimator?.duration = (Math.abs(xVelocity) / 10).toLong()
        endAnimator?.addUpdateListener { animator ->
            moveX += (animator.animatedValue) as Int
            if (moveX >= viewWidth / 2) {
                moveX = (viewWidth / 2).toFloat()
            } else if (moveX < getLargeScaleMoveX(maxScale.toFloat())) {
                moveX = getLargeScaleMoveX(maxScale.toFloat())
            }
            lastMoveX = moveX
            invalidate()
        }
        endAnimator?.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                super.onAnimationEnd(animation)
                isTouchUp = true
                invalidate()
            }

            override fun onAnimationCancel(animation: Animator?) {
                super.onAnimationCancel(animation)
                isTouchUp = true
                invalidate()
            }
        })
        endAnimator?.start()
    }

    /**
     * 画尺子
     */
    private fun drawScale(canvas: Canvas) {
        canvas.translate(0f, rulerToResultSpacing)

        //确定位置
        if (firstScale != -1f) {
            //第一次进来时候的刻度位置
            moveX = getLargeScaleMoveX(firstScale)
            lastMoveX = moveX
            firstScale = -1f
        }
        //屏幕开始的刻度
        var num1 = -(moveX / scaleSpacing).toInt()
        var num2 = moveX % scaleSpacing
        canvas.save()
        rulerRight = 0f
        //判断是否滑动且手指已离开
        if (isTouchUp) {
            //计算手指抬起时，惯性滑动结束时，需要停留的刻度
            //需要移动的刻度 = 当前移动的刻度 % 刻度间距
            num2 = moveX % scaleSpacing
            if (num2 <= 0) {
                num2 = scaleSpacing - Math.abs(num2)
            }

            //
            leftScroll = Math.abs(num2).toInt()
            rightScroll = (scaleSpacing - Math.abs(num2)).toInt()

            var moveX2 = moveX - leftScroll
            if (num2 > scaleSpacing / 2) {
                moveX2 = moveX + rightScroll
            }
            if (endAnimator != null && !endAnimator!!.isRunning) {
                endAnimator = ValueAnimator.ofFloat(moveX, moveX2)
                endAnimator?.addUpdateListener { animation ->
                    moveX = animation.animatedValue as Float
                    lastMoveX = moveX
                    invalidate()
                }

                endAnimator?.duration = 300
                endAnimator?.start()
                isTouchUp = false
            }
            num1 = -(moveX / scaleSpacing).toInt()
            num2 = moveX % scaleSpacing
        }
        //
        canvas.translate(num2, 0f)
        //

        while (rulerRight < viewWidth) {
            //画大刻度
            if (num1 % scaleCount == 0) {
                //
                if ((moveX >= 0f && rulerRight < moveX - scaleSpacing)
                        || viewWidth / 2 - rulerRight <= getLargeScaleMoveX((maxScale + 1).toFloat())
                        - moveX) {

                } else {
                    //画大刻度
                    canvas.drawLine(
                            0f,
                            0f,
                            0f,
                            largeScaleHeight,
                            largeScalePaint
                    )
                    //画单位
                    scaleNumPaint.getTextBounds(
                            "${num1 / scaleCount}",
                            0,
                            "${num1 / scaleCount}".length,
                            scaleNumRect
                    )
                    canvas.drawText(
                            "${num1 / scaleCount}",
                            (-scaleNumRect.width() / 2).toFloat(),
                            largeScaleHeight + middleScaleHeight / 2 + scaleNumRect.height(),
                            scaleNumPaint
                    )
                }
            } else {
                //①因为默认尺子的初始刻度位置在屏幕中央，所以根据@link{firstScale}获取的moveX的值>0时,不画在坐标的刻度
                //②手指滑动时判断中央位置是否已到最小值
                if ((moveX >= 0f && rulerRight < moveX)
                        || viewWidth / 2 - rulerRight < getLargeScaleMoveX(maxScale.toFloat()) - moveX) {

                } else {
                    //画小刻度
                    canvas.drawLine(
                            0f,
                            0f,
                            0f,
                            smallScaleHeight,
                            smallScalePaint
                    )
                    //画中刻度
                    if (num1 % (scaleCount / 2) == 0) {
                        canvas.drawLine(
                                0f,
                                0f,
                                0f,
                                middleScaleHeight,
                                middleScalePaint
                        )
                    }
                }

            }
            //记录当前canvas的x的位置
            rulerRight += scaleSpacing
            //刻度++
            ++num1
            //平移一个小刻度
            canvas.translate(scaleSpacing, 0f)
        }
        //在屏幕中央画一道线，表示当前选择的刻度
        canvas.restore()
        canvas.drawLine(
                (viewWidth / 2).toFloat(),
                0f,
                (viewWidth / 2).toFloat(),
                largeScaleHeight,
                scaleNumPaint
        )
    }

    /**
     * 画背景
     */
    private fun drawBG(canvas: Canvas) {
        bgRect.set(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
        canvas.drawRoundRect(bgRect, bgRadius, bgRadius, bgPaint)
    }

    /**
     * 获取大刻度移动的距离
     * @param scale 以大刻度为单位
     */
    private fun getLargeScaleMoveX(scale: Float): Float {
        return viewWidth / 2 - scaleSpacing * scaleCount * (scale - minScale)
    }
}